package com.todoclipse.dao;

import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import com.todoclipse.common.DaoException;
import com.todoclipse.common.Request;
import com.todoclipse.common.DaoException.ErrorType;
import com.todoclipse.common.Request.KeyValue;

public class UserDaoImpl implements UserDao {
	private static final int MIN_PASS_LENGTH = 5;
	private Request request = null;

	protected UserDaoImpl(Request request) {
		this.request = request;
	}

	/* (non-Javadoc)
	 * @see com.todoclipse.dao.UserDao#userRegister(java.lang.String, java.lang.String, java.lang.String, java.util.TimeZone)
	 */
	public String userRegister(String email, String password, String fullName, TimeZone timeZone) throws DaoException {
		/*
		 * User register A HTTPS request is sent to register with email,
		 * full_name, password and timezone (timezone must be one of
		 * getTimezones). Password must be at least 5 characters long.
		 * https://todoist.com/API/register?email=...&password=...&full_name=...&timezone=...
		 * User info and token is returned on success:
		 * [{"jabber":null,"msn":null,"tz_offset":["+02:00",2,0,1],"id":120491,"twitter":null,"timezone":"Europe\/Warsaw","default_reminder":null,"mobile_number":null,"email":"todoclipse@test.pl","mobile_host":null,"start_page":"_info_page","api_token":"2a94e4019ad67e846dafc949d541ca4ca10cfa6d","date_format":1,"time_format":1,"sort_order":0,"premium_until":null,"full_name":"Test"}]
		 *  or if not succeful, an error is returned: "ALREADY_REGISTRED", "TOO_SHORT_PASSWORD",
		 * "INVALID_EMAIL", "INVALID_TIMEZONE", "INVALID_FULL_NAME",
		 * "UNKNOWN_ERROR"
		 */

		if(email == null){
			throw new NullPointerException("email can not be null!");
		}
		if(password == null){
			throw new NullPointerException("password can not be null!");
		}
		if(fullName == null){
			throw new NullPointerException("full name can not be null!");
		}
		if(timeZone == null){
			throw new NullPointerException("time zone can not be null!");
		}

		KeyValue[] queryParams=new KeyValue[]{
				new KeyValue("email",email),
				new KeyValue("password",password),
				new KeyValue("full_name",fullName),
				new KeyValue("timezone", timeZone.getID())
		};
		
		return readString("register", queryParams, "api_token");
	}

	
	/*
	 * (non-Javadoc)
	 * @see com.todoclipse.dao.UserDao#changeEmail(java.lang.String, java.lang.String)
	 */
	public String changeEmail(String email, String token) throws DaoException {
		/*
		 * User update A HTTPS request is sent to updateUser with one of these
		 * parameters email, full_name, password. Password must be at least 5
		 * characters long.https://todoist.com/API/updateUser?token=
		 * fb5f22601ec566e48083213f7573e908a7a272e5...&full_name=Aloha Update
		 * user info and token is returned on success: {"email": "...", "token":
		 * ..., ...} or if not succeful, an error is returned:
		 * "ERROR_PASSWORD_TOO_SHORT", "ERROR_EMAIL_FOUND"
		 */
		if(email == null){
			throw new NullPointerException("email can not be null!");
		}
		if(token == null){
			throw new NullPointerException("token can not be null!");
		}

		KeyValue[] queryParams=new KeyValue[]{
				new KeyValue("email",email),
				new KeyValue("token",token)
		};

		return readString("updateUser", queryParams,"api_token");
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.todoclipse.dao.UserDao#changeFullName(java.lang.String, java.lang.String)
	 */
	public String changeFullName(String fullName, String token) throws DaoException {
		/*
		 * User update A HTTPS request is sent to updateUser with one of these
		 * parameters email, full_name, password. Password must be at least 5
		 * characters long.https://todoist.com/API/updateUser?token=
		 * fb5f22601ec566e48083213f7573e908a7a272e5...&full_name=Aloha Update
		 * user info and token is returned on success: {"email": "...", "token":
		 * ..., ...} or if not succeful, an error is returned:
		 * "ERROR_PASSWORD_TOO_SHORT", "ERROR_EMAIL_FOUND"
		 */
		if(fullName == null){
			throw new NullPointerException("full name can not be null!");
		}
		if(token == null){
			throw new NullPointerException("token can not be null!");
		}

		KeyValue[] queryParams=new KeyValue[]{
				new KeyValue("full_name",fullName),
				new KeyValue("token",token)
		};

		return readString("updateUser", queryParams,"api_token");
	}
	
	
	public String changePassword(String password, String token) throws DaoException {
		/*
		 * User update A HTTPS request is sent to updateUser with one of these
		 * parameters email, full_name, password. Password must be at least 5
		 * characters long.https://todoist.com/API/updateUser?token=
		 * fb5f22601ec566e48083213f7573e908a7a272e5...&full_name=Aloha Update
		 * user info and token is returned on success: {"email": "...", "token":
		 * ..., ...} or if not succeful, an error is returned:
		 * "ERROR_PASSWORD_TOO_SHORT", "ERROR_EMAIL_FOUND"
		 */
		if(password == null){
			throw new NullPointerException("password can not be null!");
		}
		if(password.length() < MIN_PASS_LENGTH){
			throw new DaoException(ErrorType.TOO_SHORT_PASSWORD,"password too short!");
		}
		if(token == null){
			throw new NullPointerException("token can not be null!");
		}

		KeyValue[] queryParams=new KeyValue[]{
				new KeyValue("password",password),
				new KeyValue("token",token)
		};

		return readString("updateUser", queryParams,"api_token");
	}

	/*
	 * (non-Javadoc)
	 * @see com.todoclipse.dao.UserDao#userLogin(java.lang.String, java.lang.String)
	 */
	public String userLogin(String email, String password) throws DaoException {
		/*
		 * User login A HTTPS request is sent to login with email and password.
		 * https://todoist.com/API/login?email=...&password=... User info and
		 * token is returned on success: {"email": "...", "token": ..., ...} or
		 * if not succeful: LOGIN_ERROR
		 */
		if(email == null){
			throw new NullPointerException("email can not be null!");
		}
		if(password == null){
			throw new NullPointerException("password can not be null!");
		}

		KeyValue[] queryParams=new KeyValue[]{
				new KeyValue("email",email),
				new KeyValue("password",password)
		};

		return readString("login", queryParams,"api_token");
	}

	private String readString(String method,KeyValue[] queryParams, String key) throws DaoException {
		JSONArray array = request.invoke(method, queryParams);
		if(array == null){
			throw new NullPointerException("Request implementation returned bad result!");
		}

		if(array.size() == 0){
			throw new DaoException(ErrorType.UNKNOWN_ERROR);
		}
		Object object = array.get(0);
		if(object instanceof String){
			String status = (String) object;			
			ErrorType errorType = null;
			try{
				errorType = ErrorType.valueOf(status);
			}catch (IllegalArgumentException e) {
				errorType = ErrorType.UNKNOWN_ERROR;
			}
			throw new DaoException(errorType);


		}else{
			JSONObject json = (JSONObject) object;
			return (String) json.get(key);
		}
	}

	/* (non-Javadoc)
	 * @see com.todoclipse.dao.UserDao#getTimezones()
	 */
	public Set<TimeZone> getTimezones() {
		/*
		 * Get timezones A request is sent to getTimezones to return the
		 * timezones Todoist supports: http://todoist.com/API/getTimezones JSON
		 * data is returned: ["US/Alaska", "US/Arizona", "US/Central",
		 * "US/Eastern", ...]
		 */
		Set<TimeZone> result = new HashSet<TimeZone>();
		JSONArray array = request.invoke("getTimezones", null);
		for (Object object : array) {
			result.add(TimeZone.getTimeZone((String)object));
		}
		return result;
	}

}
